package org.wheel.plugins.starter.jdbc.pool.service.impl;

import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.wheel.module.core.entity.vo.Message;
import org.wheel.module.core.request.ApiParam;
import org.wheel.module.core.util.Page;
import org.wheel.plugins.starter.jdbc.pool.config.DaoFactory;
import org.wheel.plugins.starter.jdbc.pool.dao.IBaseDao;
import org.wheel.plugins.starter.jdbc.pool.service.BaseService;
import org.wheel.plugins.toolkit.sql.core.LambdaDeleteWrapper;
import org.wheel.plugins.toolkit.sql.core.LambdaQueryWrapper;
import org.wheel.plugins.toolkit.sql.core.LambdaUpdateWrapper;
import org.wheel.plugins.toolkit.sql.core.Wrappers;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * 通用 Service 层实现
 * @param <T> 实体类型
 */
public class BaseServiceImpl<D extends IBaseDao<T>, T> implements BaseService<T> {

    /**
     * 子类必须暴露对应的 dao
     */
    @Autowired
    protected D baseDao;

    private Class<T> entityClass;

    private Class<D> daoClass;

    @PostConstruct
    public void init(){
        // 获取泛型参数类型
        Type genericSuperclass = this.getClass().getGenericSuperclass();
        if (genericSuperclass instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            if (actualTypeArguments.length > 0) {
                this.daoClass = (Class<D>) actualTypeArguments[0];
            }
            if (actualTypeArguments.length > 1) {
                this.entityClass = (Class<T>) actualTypeArguments[1];
            }
        }
    }
    /* ---------- 查询 ---------- */

    @Override
    public Message selectByParam(LambdaQueryWrapper<T> wrapper, ApiParam apiParam) {
        return baseDao.selectByParam(wrapper, apiParam);
    }

    @Override
    public <E> Message selectByParam(LambdaQueryWrapper<T> wrapper, ApiParam apiParam, Class<E> targetClass) {
        return baseDao.selectByParam(wrapper, apiParam, targetClass);
    }

    @Override
    public T getById(Serializable id) {
        return baseDao.selectById(id);
    }

    @Override
    public <E> E getById(Serializable id, Class<E> beanClass) {
        return baseDao.selectById(id, beanClass);
    }

    @Override
    public List<T> listByIds(Collection<? extends Serializable> ids) {
        return baseDao.selectBatchIds(ids);
    }
    @Override
    public <E> List<E> listByIds(Collection<? extends Serializable> ids, Class<E> beanClass) {
        return baseDao.selectBatchIds(ids, beanClass);
    }

    @Override
    public T getOne(LambdaQueryWrapper<T> wrapper) {
        return baseDao.selectOne(wrapper);
    }

    @Override
    public <E> E getOne(LambdaQueryWrapper<T> wrapper, Class<E> beanClass) {
        return baseDao.selectOne(wrapper, beanClass);
    }
    @Override
    public List<T> listAll(LambdaQueryWrapper<T> wrapper){
        return baseDao.selectListAll(wrapper);
    }
    @Override
    public <E> List<E> listAll(LambdaQueryWrapper<T> wrapper, Class<E> beanClass){
        return baseDao.selectListAll(wrapper, beanClass);
    }
    @Override
    public List<T> list(LambdaQueryWrapper<T> wrapper) {
        return baseDao.selectList(wrapper);
    }

    @Override
    public <E> List<E> list(LambdaQueryWrapper<T> wrapper, Class<E> beanClass) {
        return baseDao.selectList(wrapper, beanClass);
    }

    @Override
    public long count(LambdaQueryWrapper<T> wrapper) {
        return baseDao.selectCount(wrapper);
    }

    @Override
    public boolean exists(LambdaQueryWrapper<T> wrapper) {
        return baseDao.exists(wrapper);
    }

    /* ---------- 分页 ---------- */

    @Override
    public <E> Page<E> page(Page<E> page, LambdaQueryWrapper<T> wrapper, Class<E> targetClass) {
        return baseDao.selectPage(page, wrapper, targetClass);
    }

    @Override
    public Page<T> page(Page<T> page, LambdaQueryWrapper<T> wrapper) {
        return page(page, wrapper, entityClass);
    }

    /* ---------- 新增 ---------- */

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(T entity) {
        return baseDao.insert(entity) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(T entity, String opUserId) {
        return baseDao.insert(entity, opUserId) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public T saveAndGetId(T entity) {
        return baseDao.insertAndGetId(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public T saveAndGetId(T entity, String opUserId) {
        return baseDao.insertAndGetId(entity, opUserId);
    }

    /* ---------- 修改 ---------- */

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(T entity) {
        return this.updateById(entity, true);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(T entity, String opUserId) {
        return this.updateById(entity, true, opUserId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(T entity, boolean updateIgnoreNull) {
        return this.updateById(entity, updateIgnoreNull, null);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(T entity, boolean updateNull, String opUserId){
        return baseDao.updateById(entity, updateNull, opUserId) > 0;
    }

    /* ---------- 删除 ---------- */

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeById(Serializable id) {
        return baseDao.deleteById(id) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean remove(LambdaDeleteWrapper<T> wrapper) {
        return baseDao.delete(wrapper) > 0;
    }

    /* ---------- 批量操作 ---------- */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveBatch(Collection<T> entityList) {
        return Arrays.stream(baseDao.insertBatch(entityList)).anyMatch(i -> i > 0);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveBatch(Collection<T> entityList, String opUserId) {
        return Arrays.stream(baseDao.insertBatch(entityList, opUserId)).anyMatch(i -> i > 0);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateBatchById(Collection<T> entityList) {
        return Arrays.stream(baseDao.updateBatch(entityList, true)).anyMatch(i -> i > 0);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateBatchById(Collection<T> entityList, String opUserId) {
        return Arrays.stream(baseDao.updateBatch(entityList, opUserId)).anyMatch(i -> i > 0);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeBatchByIds(Collection<? extends Serializable> idList) {
        return Arrays.stream(baseDao.deleteBatchIds(idList)).anyMatch(i -> i > 0);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeBatch(Collection<T> entities) {
        if (entities != null && !entities.isEmpty()) {
            List<LambdaDeleteWrapper<T>> delList = entities.stream()
                    .map(entity -> Wrappers.lambdaDelete(entity.getClass()).delete(entity)).toList();
            return Arrays.stream(baseDao.delete(delList)).anyMatch(i -> i > 0);
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeBatchWrapper(Collection<LambdaDeleteWrapper<T>> wrappers) {
        return Arrays.stream(baseDao.delete(wrappers)).anyMatch(i -> i > 0);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean logicRemoveBatchByIds(Collection<? extends Serializable> idList, String opUserId) {
        return Arrays.stream(baseDao.logicDeleteBatchIds(idList, opUserId)).anyMatch(i -> i > 0);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean logicRemoveBatch(Collection<T> entities, String opUserId) {
        if (entities != null && !entities.isEmpty()) {
            List<LambdaUpdateWrapper<T>> delList = entities.stream()
                    .map(entity -> Wrappers.lambdaUpdate(entity.getClass()).update(entity)).toList();
            return Arrays.stream(baseDao.logicDelete(delList, opUserId)).anyMatch(i -> i > 0);
        }
        return false;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean logicRemoveBatchWrapper(Collection<LambdaUpdateWrapper<T>> wrappers, String opUserId) {
        return Arrays.stream(baseDao.logicDelete(wrappers, opUserId)).anyMatch(i -> i > 0);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean logicRemove(LambdaUpdateWrapper<T> wrapper, String opUserId) {
        return baseDao.logicRemove(wrapper, opUserId) > 0;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean logicRemoveById(Serializable id, String opUserId) {
        return baseDao.logicRemoveById(id, opUserId) > 0;
    }

    public void injectDao(DaoFactory baseDaoFactory) {
//        this.baseDao = (D) baseDaoFactory.getBaseDao(entityClass);
        try {
            this.baseDao = (D) baseDaoFactory.getObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
